﻿using System;
using System.Collections.Generic;
using STeaL.Functional;

namespace STeaL.Algorithm {
  public static partial class IListExtensions {
#region min_element
    public static int min_element<T>(this IList<T> list, int first, int last, Func<T,T,bool> pred ) {
      int pos = first;
      if ( first != last ) {
        while ( ++first != last ) {
          if ( pred(list[first], list[pos]) ) {
            pos = first;
          }
        }
      }
      return pos;
    }

    public static int min_element<T>(this IList<T> list, Func<T,T,bool> pred ) {
      return min_element(list, 0, list.Count, pred);
    }

    public static int min_element<T>(this IList<T> list, int first, int last) where T : IComparable<T> {
      return min_element(list, first, last, rel_op.less<T>);
    }

    public static int min_element<T>(this IList<T> list) where T : IComparable<T> {
      return min_element(list, 0, list.Count, rel_op.less<T>);
    }

#endregion
#region max_element
    public static int max_element<T>(this IList<T> list, int first, int last, Func<T,T,bool> pred ) {
      int pos = first;
      if ( first != last ) {
        while ( ++first != last ) {
          if ( pred(list[pos], list[first]) ) {
            pos = first;
          }
        }
      }
      return pos;
    }

    public static int max_element<T>(this IList<T> list, Func<T,T,bool> pred ) {
      return max_element(list, 0, list.Count, pred);
    }

    public static int max_element<T>(this IList<T> list, int first, int last) where T : IComparable<T> {
      return max_element(list, first, last, rel_op.less<T>);
    }

    public static int max_element<T>(this IList<T> list) where T : IComparable<T> {
      return max_element(list, 0, list.Count, rel_op.less<T>);
    }

#endregion
#region minmax_element
    public static Tuple<int,int> minmax_element<T>(this IList<T> list, int first, int last, Func<T,T,bool> pred ) {
      int minpos = first;
      int maxpos = first;
      if ( first != last ) {
        while ( ++first != last ) {
          if ( pred(list[maxpos], list[first]) ) {
            maxpos = first;
          }
          if ( pred(list[first], list[minpos]) ) {
            minpos = first;
          }
        }
      }
      return new Tuple<int,int>(minpos,maxpos);
    }

    public static Tuple<int,int> minmax_element<T>(this IList<T> list, Func<T,T,bool> pred ) {
      return minmax_element(list, 0, list.Count, pred);
    }

    public static Tuple<int,int> minmax_element<T>(this IList<T> list, int first, int last) where T : IComparable<T> {
      return minmax_element(list, first, last, rel_op.less<T>);
    }

    public static Tuple<int,int> minmax_element<T>(this IList<T> list) where T : IComparable<T> {
      return minmax_element(list, 0, list.Count, rel_op.less<T>);
    }

#endregion
  }
}
